package MyArrayList;

import java.util.Arrays;
import java.util.Iterator;
import java.util.stream.Stream;

public class ImitateArray<E> implements Iterable<E>{
    private int defaultSize = 10;
    private Object[] myArraylist= {};
    private int size = 0;

    public ImitateArray() {
    }
    //添加元素
    public boolean add(E e){
        if (size == 0){
            myArraylist = new Object[defaultSize];
        }
        //先判断是否需要扩容
        if (isExpansion()) {
            expansion();
          }
        myArraylist[size] = e;
        size++;
        return true;
    }

    //根据索引来查询数据
    public E get(int index){
        if (index >= size || index < 0){
            throw new RuntimeException("越界！！！");
        }
        return (E)myArraylist[index];
    }

    //根据索引删除数据
    public boolean remove(int index){
        if (index >= size || index < 0){
            throw new RuntimeException("越界！！！");
        }
        if (index == size - 1){
            myArraylist[index] = null;
        }else {
            //1,2,3,4,5
            //0,1,2,3,4
/*            for (int i = index; i < size; i++) {
                myArraylist[i] = myArraylist[i + 1];
            }*/
            System.arraycopy(myArraylist,index + 1,myArraylist,index,size - index -1);
        }
        size--;
        return true;
    }

    //根据索引来更改数据
    public E set(int index,E e){
        if (index >= size || index < 0){
            throw new RuntimeException("越界！！！");
        }
        E temp = (E) myArraylist[index];
        myArraylist[index] = e;
        return temp;
    }

    //数组长度
    public int size(){
        return size;
    }

    //实现forEach
    public void forEach(Consumer<E> consumer) {
        Object[] temp = new Object[size];
        for (int i = 0; i < size; i++) {
            temp[i] = myArraylist[i];
        }
        for (Object o : temp) {
            consumer.accept((E)o);
        }

    }

    //根据索引插入元素
    public boolean insert(int index,E e){
        if (index > size || index < 0){
            throw new RuntimeException("越界！！！");
        }
        if (index == size){
            //直接调用 add 方法
            add(e);
        }
        if (isExpansion()){
            expansion();
        }
        //Object[] temp = new Object[defaultSize];
/*        for (int i = 0; i < index; i++) {
            temp[i] = myArraylist[i];
        }
        temp[index] = e;
        for (int i = index; i < size ; i++) {
            temp[i+1] = myArraylist[i];
        }*/
        System.arraycopy(myArraylist,index ,myArraylist,index + 1,size - index);
        myArraylist[index] = e;
        //myArraylist = temp;
        size++;
        return true;
    }

    //是否需要扩容
    private boolean isExpansion(){
        return size >= defaultSize;
    }
    //数组扩容
    private boolean expansion(){
        defaultSize = (int) (defaultSize * 1.5);
        Object[] temp = new Object[(int) (defaultSize)];
/*        for (int i = 0; i < myArraylist.length; i++) {
            temp[i] = myArraylist[i];
        }*/
        System.arraycopy(myArraylist,0,temp,0,size);
        myArraylist = temp;
        System.out.println("扩容成功！");
        return true;
    }
    //重写 toString 方法
    @Override
    public String toString() {
        Object[] temp = new Object[size];
        for (int i = 0; i < size; i++) {
            temp[i] = myArraylist[i];
        }
        return "ImitateArray{" +
                "myArraylist=" + Arrays.toString(temp) +
                '}';
    }

    //重写迭代器
    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            int i = 0;
            @Override
            public boolean hasNext() {
                return i < size;
            }

            @Override
            public E next() {
                return (E) myArraylist[i++];
            }
        };
    }

    //用流进行遍历
    public Stream stream(){
        //第一种比较晦涩难懂
        //return Arrays.stream(Arrays.copyOf(myArraylist,size)).map(e->(E) e);

        //第二种比较好理解一点
        Stream<Object> stream1 = Stream.of(Arrays.copyOf(myArraylist,size));
        return stream1.map(e->(E) e);
    }
}
